package com.legendframework.dao.support;

import com.legendframework.dao.annotation.Column;
import com.legendframework.dao.annotation.TableId;
import com.legendframework.dao.exception.DaoException;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class ClassUtils {

    /**
     * 获取这个类的所有字段
     *
     * 包括所有父类的
     *
     * @param entityClass 类
     * @return 所有字段
     */
    public static List<Field> getByClass(Class<?> entityClass){
        List<Field> fields = new ArrayList<>(Arrays.asList(entityClass.getDeclaredFields()));
        if (Object.class.equals(entityClass.getSuperclass())){
            return fields;
        }
        List<Field> superFields = getByClass(entityClass.getSuperclass());
        for (Field superField : superFields) {
            if (fields.stream().map(Field::getName).collect(Collectors.toList()).contains(superField.getName())){
                continue;
            }
            fields.add(superField);
        }
        return fields;
    }

    /**
     * 获取该字段的get方法
     * @param entityClass 类
     * @param field 字段
     * @return
     */
    public static Method getGetterMethodByField(Class<?> entityClass , Field field){
        try {
            return entityClass.getMethod("get"+field.getName().substring(0,1).toUpperCase()+field.getName().substring(1));
        } catch (NoSuchMethodException e) {
            throw new DaoException("获取字段get方法时失败,字段名:"+field.getName());
        }
    }

    /**
     * 获取该字段的set方法
     * @param entityClass 类
     * @param field 字段
     * @return
     */
    public static Method getSetterMethodByField(Class<?> entityClass , Field field){
        try {
            return entityClass.getMethod("set"+field.getName().substring(0,1).toUpperCase()+field.getName().substring(1),field.getType());
        } catch (NoSuchMethodException e) {
            throw new DaoException("获取字段set方法时失败,字段名:"+field.getName());
        }
    }

    /**
     * 获取泛型对象的指定字段值的Value
     * @param t 实体类对象
     * @param fieldName 字段名称
     * @param <T>
     * @return
     */
    public static <T> Object getFieldValue(T t , String fieldName){
        Class<?> cls = t.getClass();
        Field field = null;
        List<Field> fields = getByClass(cls);
        for (Field declaredField : fields) {
            if (declaredField.isAnnotationPresent(Column.class)) {
                Column annotation = declaredField.getAnnotation(Column.class);
                if (annotation.exist() && annotation.value().equals(fieldName)) {
                    field = declaredField;
                    break;
                }
            }
        }
        if (field == null) {
            for (Field declaredField : fields) {
                if (declaredField.getName().equals(fieldName)) {
                    field = declaredField;
                    break;
                }
            }
        }
        if (field == null) {
            throw new DaoException(String.format("该对象没有这给字段: %s , %s",cls.getName(),fieldName));
        }
        try {
            return getGetterMethodByField(cls,field).invoke(t);
        } catch (Throwable e) {
            throw new DaoException(String.format("获取对象字段值失败: %s , %s",cls.getName(),fieldName));
        }
    }
    /**
     * 获取实体类中的ID
     * @param entity 实体类对象
     * @return
     */
    public static <T> Serializable getIdByEntity(T entity){
        Field idField = null;
        for (Field field : ClassUtils.getByClass(entity.getClass())) {
            if (field.isAnnotationPresent(TableId.class)) {
                idField = field;
                break;
            }
        }
        if (idField == null) {
            throw new DaoException("当前实体类没有ID字段: "+entity.getClass());
        }
        if (!Serializable.class.isAssignableFrom(idField.getType())) {
            throw new DaoException("实体类的ID字段必须实现序列化接口: "+entity.getClass());
        }
        idField.setAccessible(true);
        try {
            return (Serializable) idField.get(entity);
        } catch (IllegalAccessException e) {
            throw new DaoException("获取ID字段值失败: "+entity.getClass());
        }
    }


}
